const parser = require("@babel/parser");
const fs = require("fs");
const path = require("path");
const traverse = require("@babel/traverse").default;
const { transformFromAst, transformFromAstSync } = require("@babel/core");
const webpackConfig = require("../webpack.config");
module.exports = class Webpack {
  constructor(options) {
    // console.log(options);
    const { entry, output } = options;
    this.entry = entry;
    this.output = output;
    this.modules = [];
  }
  run() {
    // 启动函数
    const info = this.parse(this.entry);
    // console.log(info);
    this.modules.push(info);

    for (var i = 0; i < this.modules.length; i++) {
      const item = this.modules[i];
      const {yilai} = item;
      if (yilai) {
        for (let j in yilai) {
          // ./src/a.js
          // ./src/b.js
          this.modules.push(this.parse(yilai[j]));
        }
      }
    }

    // console.log(this.modules);

    // 数组结构转换
    const obj = {};
    this.modules.forEach(item => {
      obj[item.entryFile] = {
        yilai: item.yilai,
        code: item.code
      };
    });

    console.log(obj);
    this.file(obj);
  }
  /**
   * 编译文件
   * @param {string} entryFile 入口文件地址
   * @returns 
   */
  parse(entryFile) {
    const yilai = {};
    const content = fs.readFileSync(entryFile, "utf-8");
    const ast = parser.parse(content, {
      sourceType: "module",
    });
    // console.log(ast.program.body);
    traverse(ast, {
      ImportDeclaration({ node }) {
        // console.log(node);
        // dependencies.push(node.source.value);
        // 在项目中的路径
        const newFilename =
          "./" + path.join(path.dirname(entryFile), node.source.value);
        yilai[node.source.value] = newFilename;
      },
    });
    // console.log(dependencies);
    // 加工厂
    const {code} = transformFromAstSync(ast, null, {
      // 要把ast处理成什么标准的代码
      presets: ["@babel/preset-env"]
    });

    // console.log(code);
    return {
      entryFile,
      yilai,
      code
    };
  }

  /**
   * 代码生成
   * @param {*} code 
   */
  file(code) {
    const filePath = path.join(webpackConfig.output.path, webpackConfig.output.filename);
    console.log(filePath);
    const bundle = `(function (graph) {
      // 声明require函数
      function require (module) { //! 这里的module是相对于项目的路径 ./src/index.js 下面传入的入口文件地址
        // 定义exports, 防止报exports为定义错误
        var exports = {};
        function localRequire (relativePath) {
          return require(graph[module].yilai[relativePath]);
        }
        (function (require, exports, code) {
          eval(code);
        })(localRequire, exports, graph[module].code);

        return exports;
      }
      // 让他知道从哪里开始执行
      require('${this.entry}');
    })(${JSON.stringify(code)})`;
    // 生成文件
    fs.writeFileSync(filePath, bundle, 'utf-8');
  }
};
